Chapter 5: Practical Game Development
Want to use AI to develop games? Let's use Cursor to realize your game development dream!
1. Get started quickly by greedy snakes
1 Project Planning
Let's start with the simplest game and create a gluttonous snake with Cursor:
You: Help me make a simple snake game, write it in HTML, save it as index.html and put it in the current directory
Cursor: Let me think about how to implement a simple snake game...
First, you need to consider the basic elements of the game:
- Game area - Can be drawn with canvas element
- Snake - You can use array to store the coordinates of each part of the snake body
- Food - Random position generation
- Movement control - Need to listen to keyboard events
- Game loop - setInterval to implement
The game logic needs to include:
- Initialize the game area and the position of the snake
- Handle the movement direction
- Detect collision (wall and itself)
- The snake body becomes longer after eating food
- Game end judgment
hmm... Let me think about the code structure:
- The HTML part is very simple, only the canvas element is needed
- The JavaScript part needs:
- Initialization function
- Drawing function
- Movement function
- Food generation function
- Collision detection function
- Keyboard event processing
- Game main loop
To make the game more friendly, you can add:
- Score display
- Game over prompt
- Restart button
Okay, let me start writing code...
This is a simple implementation of the snake game, the main features include:
1. Use Canvas to draw the game screen
Use the arrow keys to control the movement of the snake
3. Contains score display function
Has basic collision detection (wall and itself)
When the game ends, the score will be displayed and automatically restarted
Game rules:
Use the keyboard arrow keys to control the movement of the snake
Eat red food to get 10 points
Hit the wall or your own body will result in the end of the game
You can save this code as an index.html file, and then open it directly in the browser to start the game.
2 Core code generation
🎮 Game subject
<!DOCTYPE html>
<html>
<head>
<title>贪吃蛇游戏</title>
<style>
canvas {
border: 2px solid black;
}
.game-container {
text-align: center;
margin-top: 20px;
}
#score {
font-size: 24px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="game-container">
<div id="score">分数: 0</div>
<canvas id="gameCanvas" width="400" height="400"></canvas>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const gridSize = 20;
const tileCount = 20;
let snake = [
{x: 10, y: 10},
];
let food = {x: 15, y: 15};
let dx = 0;
let dy = 0;
let score = 0;
let gameLoop;
// 初始化游戏
function startGame() {
snake = [{x: 10, y: 10}];
food = {x: 15, y: 15};
dx = 0;
dy = 0;
score = 0;
updateScore();
if (gameLoop) clearInterval(gameLoop);
gameLoop = setInterval(gameUpdate, 100);
}
// 更新分数显示
function updateScore() {
scoreElement.textContent = `分数: ${score}`;
}
// 游戏主循环
function gameUpdate() {
// 移动蛇
const head = {x: snake[0].x + dx, y: snake[0].y + dy};
snake.unshift(head);
// 检查是否吃到食物
if (head.x === food.x && head.y === food.y) {
score += 10;
updateScore();
generateFood();
} else {
snake.pop();
}
// 检查游戏是否结束
if (checkCollision()) {
alert(`游戏结束!最终得分:${score}`);
startGame();
return;
}
// 清空画布
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制食物
ctx.fillStyle = 'red';
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize-2, gridSize-2);
// 绘制蛇
ctx.fillStyle = 'green';
snake.forEach(segment => {
ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize-2, gridSize-2);
});
}
// 生成新的食物
function generateFood() {
food = {
x: Math.floor(Math.random() * tileCount),
y: Math.floor(Math.random() * tileCount)
};
// 确保食物不会生成在蛇身上
if (snake.some(segment => segment.x === food.x && segment.y === food.y)) {
generateFood();
}
}
// 碰撞检测
function checkCollision() {
const head = snake[0];
// 检查是否撞墙
if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
return true;
}
// 检查是否撞到自己
for (let i = 1; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
return true;
}
}
return false;
}
// 键盘控制
document.addEventListener('keydown', event => {
switch (event.key) {
case 'ArrowUp':
if (dy === 0) {
dx = 0;
dy = -1;
}
break;
case 'ArrowDown':
if (dy === 0) {
dx = 0;
dy = 1;
}
break;
case 'ArrowLeft':
if (dx === 0) {
dx = -1;
dy = 0;
}
break;
case 'ArrowRight':
if (dx === 0) {
dx = 1;
dy = 0;
}
break;
}
});
// 开始游戏
startGame();
</script>
</body>
</html>
3 Running effect
4 Quick iteration optimization
You: The snake's movement is a bit jerky
Cursor: Let me think about how to improve the smoothness of the movement of the snake game...
First, the reason for the lag may be that the game loop is not updating frequently enough. The current setting is to update every 100 milliseconds, which may cause the movement to be not smooth enough. Consider setting this interval to a shorter time, such as setting it to update every 50 milliseconds.
Secondly, you may also need to check the efficiency of your drawing and make sure that only the necessary parts are updated each time you draw, rather than redrawing the entire canvas. Although redrawing the entire canvas is common practice in this simple implementation, it is important to optimize the drawing logic in more complex games.
Finally, make sure that the processing of keyboard events does not cause delays. Consider using `requestAnimationFrame` instead of `setInterval`, which will make the browser call the game update function every time it redraws, thereby improving smoothness.
OK, let me modify the code to improve smoothness...
...
After this modification, the game movement should be smoother. You can apply these changes to your code to see how it works.
💡 Featured Features
- Gradually difficult: gradually speed up after eating food
- Special food: Randomly available bonus props
- Obstacles: Randomly generated walls increase difficulty
- Scoreboard: Record the highest score
🌟 Development skills
- Realize the most basic movement and collision first
- Gradually add food and scoring systems
- Finally, optimize the visual effect and operation feel
2 Tetris Miracle
1 Demand Analysis and Planning
First, let's tell Cursor what we want in natural language:
You: I want to develop a classic Tetris game, written in HTML, saved as index.html and placed in the current directory
Cursor: Let me think about how to implement a classic Tetris game...
First, the basic elements of Tetris include:
- Game area - Can be drawn using the canvas element
- Blocks - Need to define blocks of different shapes (such as I, O, T, L, J, S, Z)
- Movement and rotation of blocks - Need to listen to keyboard events to control
- Game loop - Use setInterval or requestAnimationFrame to update the game state
- Collision detection - Check if the block overlaps with the border or other blocks
- Eliminate a row - When a row is filled, eliminate the row and update the score
The game logic needs to include:
- Initialize the game area and blocks
- Handle the falling, moving and rotating of blocks
- Detect whether the row is filled and eliminate it
- Update the score and game state
- Game end judgment
To make the game more friendly, you can add:
- Score display
- Game end prompt
- Restart button
Okay, let me start writing code...
This is a simple Tetris game implementation, the main features include:
Use Canvas to draw the game screen.
2. Support the movement and rotation of the blocks.
3. Detect whether the row is filled and eliminate it.
Display the score.
When the game ends, the score will be displayed and the game will be reset.
You can save this code as index.html file and open it directly in the browser to start the game.
2 Code generation and implementation
🎮 Core code generation
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>经典俄罗斯方块</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
canvas {
border: 2px solid black;
background-color: white;
}
#score {
text-align: center;
font-size: 24px;
margin-top: 10px;
}
</style>
</head>
<body>
<div>
<canvas id="gameCanvas" width="300" height="600"></canvas>
<div id="score">分数: 0</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const gridSize = 30; // 每个方块的大小
const rows = canvas.height / gridSize; // 行数
const cols = canvas.width / gridSize; // 列数
let board = Array.from({ length: rows }, () => Array(cols).fill(0));
let score = 0;
let currentPiece;
let dropInterval = 1000; // 方块下落的时间间隔
let dropTime = 0;
// 定义方块形状
const pieces = [
[[1, 1, 1, 1]], // I
[[1, 1], [1, 1]], // O
[[0, 1, 0], [1, 1, 1]], // T
[[1, 0, 0], [1, 1, 1]], // L
[[0, 0, 1], [1, 1, 1]], // J
[[0, 1, 1], [1, 1, 0]], // S
[[1, 1, 0], [0, 1, 1]], // Z
];
// 随机生成方块
function randomPiece() {
const index = Math.floor(Math.random() * pieces.length);
return {
shape: pieces[index],
x: Math.floor(cols / 2) - 1,
y: 0,
};
}
// 绘制方块
function drawPiece(piece) {
piece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value) {
ctx.fillStyle = 'blue';
ctx.fillRect((piece.x + x) * gridSize, (piece.y + y) * gridSize, gridSize - 1, gridSize - 1);
}
});
});
}
// 检查碰撞
function collide(board, piece) {
for (let y = 0; y < piece.shape.length; y++) {
for (let x = 0; x < piece.shape[y].length; x++) {
if (piece.shape[y][x] && (board[piece.y + y] && board[piece.y + y][piece.x + x]) !== 0) {
return true;
}
}
}
return false;
}
// 将方块放入棋盘
function merge(board, piece) {
piece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value) {
board[piece.y + y][piece.x + x] = 1;
}
});
});
}
// 消行
function removeFullLines() {
let linesToRemove = [];
for (let y = 0; y < rows; y++) {
if (board[y].every(value => value !== 0)) {
linesToRemove.push(y);
}
}
linesToRemove.forEach(y => {
board.splice(y, 1);
board.unshift(Array(cols).fill(0));
score += 10;
});
scoreElement.textContent = `分数: ${score}`;
}
// 更新游戏状态
function update() {
dropTime += 16; // 每帧大约16毫秒
if (dropTime > dropInterval) {
currentPiece.y++;
if (collide(board, currentPiece)) {
currentPiece.y--;
merge(board, currentPiece);
removeFullLines();
currentPiece = randomPiece();
if (collide(board, currentPiece)) {
alert(`游戏结束!最终得分:${score}`);
resetGame();
}
}
dropTime = 0;
}
}
// 重置游戏
function resetGame() {
board = Array.from({ length: rows }, () => Array(cols).fill(0));
score = 0;
scoreElement.textContent = `分数: ${score}`;
currentPiece = randomPiece();
}
// 键盘控制
document.addEventListener('keydown', event => {
switch (event.key) {
case 'ArrowLeft':
currentPiece.x--;
if (collide(board, currentPiece)) currentPiece.x++;
break;
case 'ArrowRight':
currentPiece.x++;
if (collide(board, currentPiece)) currentPiece.x--;
break;
case 'ArrowDown':
currentPiece.y++;
if (collide(board, currentPiece)) currentPiece.y--;
break;
case 'ArrowUp':
// 旋转方块
const rotated = currentPiece.shape[0].map((_, index) => currentPiece.shape.map(row => row[index]).reverse());
const originalShape = currentPiece.shape;
currentPiece.shape = rotated;
if (collide(board, currentPiece)) {
currentPiece.shape = originalShape; // 旋转失败,恢复原形
}
break;
}
});
// 游戏主循环
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
board.forEach((row, y) => {
row.forEach((value, x) => {
if (value) {
ctx.fillStyle = 'blue';
ctx.fillRect(x * gridSize, y * gridSize, gridSize - 1, gridSize - 1);
}
});
});
drawPiece(currentPiece);
update();
requestAnimationFrame(draw);
}
// 启动游戏
currentPiece = randomPiece();
draw();
</script>
</body>
</html>
3 Running effect
4 Debugging and Optimization
🎯 Feedback Debugging
You: The blocks are falling too fast
Cursor: Let me help you adjust:
1. Modify the falling interval
2. Add difficulty progression
3. Add speed control option
🌟 Advanced tips:
- Make good use of Cursor's code generation capabilities
- Let AI help you refactor and optimize your code
- Use version control to track development progress
- Save and backup projects in a timely manner
Remember: game development is a gradual process. Cursor can be your right-hand assistant, but creativity and gameplay still need to be grasped by yourself!